﻿<div class="tab-pane fade" id="nav-jsapi" role="tabpanel" aria-labelledby="nav-profile-tab">
    <h5>JSAPI 支付</h5>
    <p>
        在微信公众号网页中使用微信支付，必须借助 JSAPI，完成支付流程。
    </p>
    <p>
        首先，需要创建一个商品页面，并在页面上提供一个下订单的入口，例如：一键购买。<br />
        （具体实现此处略）
    </p>
    <p>
        当前示例中，提供了 3 个关键的页面：ProductList（商品列表）、ProductItem（商品详情） 和 JsApi（JSAPI 订单支付）。
    </p>
    <h5>ProductList 商品列表</h5>
    <p><strong>后端</strong></p>
    <p>参考代码：TenPayV3Controller 下的 ProductList() 方法。</p>
    <pre><code>public ActionResult ProductList()
{
    var products = ProductModel.GetFakeProductList();
    return View(products);
}</code></pre>

    <figure class="file">
        <blockquote class="blockquote">
            <p>本项目参考文件：</p>
        </blockquote>
        <figcaption class="blockquote-footer">
            /<cite title="Source Title">Controllers/TenPayV3Controller.cs</cite>
        </figcaption>
    </figure>
    <p><strong>前端</strong></p>
    <figure class="file">
        <blockquote class="blockquote">
            <p>本项目参考文件：</p>
        </blockquote>
        <figcaption class="blockquote-footer">
            /<cite title="Source Title">Views/TenPayV3/ProductItem.cshtml</cite>
        </figcaption>
    </figure>
    <p><strong>效果</strong></p>
    <p><a href="/TenPayV3/ProductList" target="_blank">打开预览</a><p>
    <p>
    <p>
        <figure class="figure">
            <img src="~/images/home-dev-jsapi-01.png" class="figure-img img-fluid rounded" alt="商品列表" />
            <figcaption class="figure-caption text-center">商品列表</figcaption>
        </figure>
    </p>

    <h5>ProductItem 商品详情</h5>

    <p><strong>后端</strong></p>
    <p>参考代码：TenPayV3Controller 下的 ProductItem() 方法。</p>
    <pre><code>public ActionResult ProductItem(int productId, int hc)
{
    var products = ProductModel.GetFakeProductList();
    var product = products.FirstOrDefault(z => z.Id == productId);
    if (product == null || product.GetHashCode() != hc)
    {
        return Content("商品信息不存在，或非法进入！2003");
    }

    //判断是否正在微信端
    if (Senparc.Weixin.BrowserUtility.BrowserUtility.SideInWeixinBrowser(HttpContext))
    {
        //正在微信端，直接跳转到微信支付页面
        return RedirectToAction("JsApi", new { productId = productId, hc = hc });
    }
    else
    {
        //在PC端打开，提供二维码扫描进行支付
        return View(product);
    }
}</code></pre>

    <figure class="file">
        <blockquote class="blockquote">
            <p>说明：上述代码使用 <code>SideInWeixinBrowser()</code> 方法对当前页面的运行环境做了判断，如果是在微信内打开，则直接进入 JsApi 支付页面（见下放 JsApi 的介绍），如果在非微信内部打开（如 PC），则展示商品详情，并提供多种支付方式的选择。</p>
        </blockquote>
    </figure>

    <figure class="file">
        <blockquote class="blockquote">
            <p>本项目参考文件：</p>
        </blockquote>
        <figcaption class="blockquote-footer">
            /<cite title="Source Title">Controllers/TenPayV3Controller.cs</cite>
        </figcaption>
    </figure>
    <p><strong>前端</strong></p>
    <figure class="file">
        <blockquote class="blockquote">
            <p>本项目参考文件：</p>
        </blockquote>
        <figcaption class="blockquote-footer">
            /<cite title="Source Title">Views/TenPayV3/ProductItem.cshtml</cite>
        </figcaption>
    </figure>
    <p><strong>效果</strong></p>
    <p>从 <a href="/TenPayV3/ProductList" target="_blank">商品列表</a> 中选择一个商品点击，如果在 PC 端，则可以看到详情页面：<p>
        <figure class="figure">
            <img src="~/images/home-dev-jsapi-02.png" class="figure-img img-fluid rounded" alt="商品列表" />
            <figcaption class="figure-caption text-center">商品列表</figcaption>
        </figure>
    </p>
    <p>上述的<strong>支付方式二：“扫一扫”支付</strong>下方有一个根据所选商品自动生成的二维码，使用手机微信扫一扫，即可进入对应的商品订单页面（即 JsApi 订单页面）。</p>
    <h5>JSAPI 订单支付页面</h5>
    <p><strong>后端</strong></p>
    <p>用户点击下单按钮后，需要在后台生成一个预支付订单并在页面上登记，代码请参考 <code>TenPayV3Controller.JsApi()</code></p>
    <pre><code>[CustomOAuth(null, "/TenpayV3/OAuthCallback")]
public ActionResult JsApi(int productId, int hc)
{
    try
    {
        //获取产品信息
        //...
        //调用 JsApi 获取预支付信息
        //...

        return View();
    }
    catch (Exception ex)
    {
        //...
    }
}</code></pre>
    <figure class="file">
        <blockquote class="blockquote">
            <p>本项目参考文件：</p>
        </blockquote>
        <figcaption class="blockquote-footer">
            /<cite title="Source Title">Controllers/TenPayV3Controller.cs</cite>
        </figcaption>
    </figure>
    <p>上述代码中，传入的 <code>productId</code> 参数是商品的编号，此处作为 Sample 演示，是从内存中模拟列表并查询，实际项目中，商品信息一般存储在数据库中，根据  <code>productId</code> 从数据中查找商品数据；<code>hc</code> 函数是为了确保当前内存信息的有效性而设置的对应商品信息的 HashCode，实际开发项目中无需使用，可忽略。</p>
    <p>此过程中，最关键的代码是：<code>var result = TenPayOldV3.Unifiedorder(xmlDataInfo)</code>，<code>result.prepay_id</code> 即“预支付ID”，前端页面必须凭借 prepay_id 才能让手机端唤起微信支付。此时，当前订单编号已经在微信支付后台进行了注册。</p>

    <p>注意：该方法使用了 <strong>[CustomOAuth]</strong> 特性，用于自动使用微信公众号的 OAuth 功能识别用户身份，此功能属于公众号范畴，不在这里展开。</p>

    <p><strong>前端</strong></p>
    <p>
        前端的关键操作是当用户点击“支付”按钮后，执行 JS 代码：
    </p>
    <p>

        <pre><code>WeixinJSBridge.invoke('getBrandWCPayRequest', {
    "appId": "@ViewData["appId"]", //公众号名称，由商户传入
    "timeStamp": "@ViewData["timeStamp"]", //时间戳
    "nonceStr": "@ViewData["nonceStr"]", //随机串
    "package": "@Html.Raw(ViewData["package"])",//扩展包
    "signType": "MD5", //微信签名方式:MD5
    "paySign": "@ViewData["paySign"]" //微信签名
}, function (res) {
    if (res.err_msg == "get_brand_wcpay_request:ok") {
        //支付成功
    }
});</code></pre>

    </p>
    <p></p>
    <figure class="file">
        <blockquote class="blockquote">
            <p>本项目参考文件：</p>
        </blockquote>
        <figcaption class="blockquote-footer">
            /<cite title="Source Title">Views/TenPayV3/JsApi.cshtml</cite>
        </figcaption>
    </figure>
    <p><strong>效果</strong></p>
    <p>
        <figure class="figure">
            <img src="~/images/home-dev-jsapi-03.jpg" class="figure-img img-fluid rounded" alt="订单支付页面" />
            <figcaption class="figure-caption text-center">订单支付页面</figcaption>
        </figure>
    </p>
    <p>
        <figure class="figure">
            <img src="~/images/home-dev-jsapi-04.jpg" class="figure-img img-fluid rounded" alt="点击唤起支付" />
            <figcaption class="figure-caption text-center">点击唤起支付</figcaption>
        </figure>
    </p>
    <p>
        <figure class="figure">
            <img src="~/images/home-dev-jsapi-05.jpg" class="figure-img img-fluid rounded" alt="支付成功" />
            <figcaption class="figure-caption text-center">支付成功</figcaption>
        </figure>
    </p>

</div>